{{#useSwaggerAnnotations}}
import io.swagger.annotations.*;
{{/useSwaggerAnnotations}}
{{#useSwaggerV3Annotations}}
import io.swagger.v3.oas.annotations.media.Schema;
{{/useSwaggerV3Annotations}}
import java.util.Objects;
{{#jackson}}
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.annotation.JsonTypeName;
{{/jackson}}
{{#withXml}}
import {{javaxPackage}}.xml.bind.annotation.XmlElement;
import {{javaxPackage}}.xml.bind.annotation.XmlRootElement;
import {{javaxPackage}}.xml.bind.annotation.XmlAccessType;
import {{javaxPackage}}.xml.bind.annotation.XmlAccessorType;
import {{javaxPackage}}.xml.bind.annotation.XmlType;
import {{javaxPackage}}.xml.bind.annotation.XmlEnum;
import {{javaxPackage}}.xml.bind.annotation.XmlEnumValue;
{{/withXml}}

{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{#description}}/**
 * {{.}}
 **/{{/description}}
{{#useSwaggerAnnotations}}{{#description}}@ApiModel(description = "{{{.}}}"){{/description}}{{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
@Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
@org.eclipse.microprofile.openapi.annotations.media.Schema({{#title}}title="{{{.}}}", {{/title}}{{#description}}description="{{{.}}}"{{/description}}{{^description}}description=""{{/description}}){{/useMicroProfileOpenAPIAnnotations}}
{{#jackson}}@JsonTypeName("{{name}}"){{/jackson}}
{{>generatedAnnotation}}{{>additionalModelTypeAnnotations}}{{>xmlPojoAnnotation}}
{{#vendorExtensions.x-class-extra-annotation}}
{{{vendorExtensions.x-class-extra-annotation}}}
{{/vendorExtensions.x-class-extra-annotation}}
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}} {{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
  {{#vars}}
  {{#isEnum}}
  {{^isContainer}}
  {{>enumClass}}{{! prevent indent}}
  {{/isContainer}}
  {{#isContainer}}
  {{#mostInnerItems}}
  {{>enumClass}}{{! prevent indent}}
  {{/mostInnerItems}}
  {{/isContainer}}
  {{/isEnum}}
  {{#vendorExtensions.x-field-extra-annotation}}
  {{{.}}}
  {{/vendorExtensions.x-field-extra-annotation}}
  private {{#isContainer}}{{#useBeanValidation}}@Valid {{/useBeanValidation}}{{/isContainer}}{{{datatypeWithEnum}}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
  {{/vars}}

  {{#generateBuilders}}
  {{^additionalProperties}}
  protected {{classname}}({{classname}}Builder<?, ?> b) {
    {{#parent}}
    super(b);
    {{/parent}}
    {{#vars}}
    this.{{name}} = b.{{name}};
    {{/vars}}
  }

  {{/additionalProperties}}
  {{/generateBuilders}}
  public {{classname}}() {
  }

  {{#jackson}}
  {{#generateJsonCreator}}
  {{#hasRequired}}
  @JsonCreator
  public {{classname}}(
    {{#requiredVars}}
    @JsonProperty(required = {{required}}, value = "{{baseName}}") {{>beanValidatedType}} {{name}}{{^-last}},{{/-last}}
    {{/requiredVars}}
  ) {
    {{#parent}}
    super(
    {{#parentRequiredVars}}
      {{name}}{{^-last}},{{/-last}}
    {{/parentRequiredVars}}
    );
    {{/parent}}
    {{#vars}}
    {{#required}}
    this.{{name}} = {{name}};
    {{/required}}
    {{/vars}}
  }

  {{/hasRequired}}
  {{/generateJsonCreator}}
  {{/jackson}}
  {{#vars}}
  /**
   {{#description}}
   * {{.}}
   {{/description}}
   {{#minimum}}
   * minimum: {{.}}
   {{/minimum}}
   {{#maximum}}
   * maximum: {{.}}
   {{/maximum}}
   **/
  public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
    this.{{name}} = {{name}};
    return this;
  }

  {{#withXml}}
      @XmlElement(name="{{baseName}}"{{#required}}, required = {{required}}{{/required}})
  {{/withXml}}
  {{#vendorExtensions.x-extra-annotation}}{{{vendorExtensions.x-extra-annotation}}}{{/vendorExtensions.x-extra-annotation}}{{#useSwaggerAnnotations}}
  @ApiModelProperty({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}value = "{{{description}}}"){{/useSwaggerAnnotations}}{{#useSwaggerV3Annotations}}
  @Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useSwaggerV3Annotations}}{{#useMicroProfileOpenAPIAnnotations}}
  @org.eclipse.microprofile.openapi.annotations.media.Schema({{#example}}example = "{{{.}}}", {{/example}}{{#required}}required = {{required}}, {{/required}}description = "{{{description}}}"){{/useMicroProfileOpenAPIAnnotations}}
  {{#jackson}}@JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}"){{/jackson}}
  {{#useBeanValidation}}{{>beanValidation}}{{/useBeanValidation}}public {{>beanValidatedType}} {{getter}}() {
    return {{name}};
  }

  {{#jackson}}
  @JsonProperty({{#required}}required = {{required}}, value = {{/required}}"{{baseName}}")
  {{/jackson}}
  {{#vendorExtensions.x-setter-extra-annotation}}{{{vendorExtensions.x-setter-extra-annotation}}}
  {{/vendorExtensions.x-setter-extra-annotation}}public void {{setter}}({{{datatypeWithEnum}}} {{name}}) {
    this.{{name}} = {{name}};
  }

  {{#isArray}}
  public {{classname}} add{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
    if (this.{{name}} == null) {
      this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new {{#uniqueItems}}LinkedHashSet{{/uniqueItems}}{{^uniqueItems}}ArrayList{{/uniqueItems}}<>(){{/defaultValue}};
    }

    this.{{name}}.add({{name}}Item);
    return this;
  }

  public {{classname}} remove{{nameInPascalCase}}Item({{{items.datatypeWithEnum}}} {{name}}Item) {
    if ({{name}}Item != null && this.{{name}} != null) {
      this.{{name}}.remove({{name}}Item);
    }

    return this;
  }
  {{/isArray}}
  {{#isMap}}
  public {{classname}} put{{nameInPascalCase}}Item(String key, {{{items.datatypeWithEnum}}} {{name}}Item) {
    if (this.{{name}} == null) {
      this.{{name}} = {{{defaultValue}}}{{^defaultValue}}new HashMap<>(){{/defaultValue}};
    }

    this.{{name}}.put(key, {{name}}Item);
    return this;
  }

  public {{classname}} remove{{nameInPascalCase}}Item(String key) {
    if (this.{{name}} != null) {
      this.{{name}}.remove(key);
    }

    return this;
  }
  {{/isMap}}
  {{/vars}}

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }{{#hasVars}}
    {{classname}} {{classVarName}} = ({{classname}}) o;
    return {{#vars}}{{#isByteArray}}Arrays{{/isByteArray}}{{^isByteArray}}Objects{{/isByteArray}}.equals(this.{{name}}, {{classVarName}}.{{name}}){{^-last}} &&
        {{/-last}}{{/vars}}{{#parent}} &&
        super.equals(o){{/parent}};{{/hasVars}}{{^hasVars}}
    return {{#parent}}super.equals(o){{/parent}}{{^parent}}true{{/parent}};{{/hasVars}}
  }

  @Override
  public int hashCode() {
    return Objects.hash({{#vars}}{{^isByteArray}}{{name}}{{/isByteArray}}{{#isByteArray}}Arrays.hashCode({{name}}){{/isByteArray}}{{^-last}}, {{/-last}}{{/vars}}{{#parent}}{{#hasVars}}, {{/hasVars}}super.hashCode(){{/parent}});
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class {{classname}} {\n");
    {{#parent}}sb.append("    ").append(toIndentedString(super.toString())).append("\n");{{/parent}}
    {{#vars}}sb.append("    {{name}}: ").append({{#isPassword}}"*"{{/isPassword}}{{^isPassword}}toIndentedString({{name}}){{/isPassword}}).append("\n");
    {{/vars}}sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }

{{#generateBuilders}}{{^additionalProperties}}
  public static {{classname}}Builder<?, ?> builder() {
    return new {{classname}}BuilderImpl();
  }

  private static final class {{classname}}BuilderImpl extends {{classname}}Builder<{{classname}}, {{classname}}BuilderImpl> {

    @Override
    protected {{classname}}BuilderImpl self() {
      return this;
    }

    @Override
    public {{classname}} build() {
      return new {{classname}}(this);
    }
  }

  public static abstract class {{classname}}Builder<C extends {{classname}}, B extends {{classname}}Builder<C, B>> {{#parent}}extends {{{.}}}Builder<C, B>{{/parent}} {
    {{#vars}}
    private {{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}{{#defaultValue}} = {{{.}}}{{/defaultValue}};
    {{/vars}}
  {{^parent}}
    protected abstract B self();

    public abstract C build();
    {{/parent}}

    {{#vars}}
    public B {{name}}({{#removeAnnotations}}{{{datatypeWithEnum}}}{{/removeAnnotations}} {{name}}) {
      this.{{name}} = {{name}};
      return self();
    }
    {{/vars}}
  }{{/additionalProperties}}{{/generateBuilders}}
}
